package com.kehongborui.fliggy.util.spider;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.kehongborui.fliggy.queue.CustomQueue;
import com.kehongborui.fliggy.queue.VideoUrlQueue;
import com.kehongborui.fliggy.util.spider.model.VideoModel;

import javax.net.ssl.HttpsURLConnection;
import java.io.*;
import java.net.*;
import java.util.*;
import java.util.stream.Stream;

/**
 * @author zhang peng yang ming
 * @CopyRight (C) http://www.csdn.com
 * @brief
 * @email 122162005@qq.com
 * @date 2018-09-07
 */
public class HttpClient {
    private static String URL = "http://10.3.2.218:8080/online/page";
    private static String LOGIN_URL = "http://10.3.2.218:8080/login/checkLogin";
    private static String LOAD_DATA_URL = "http://10.3.2.218:8080/online/loadData";
    private static String LOAD_CATALOG_LIST = "http://10.3.2.218:8080/online/loadCatalogList";

    //    视频页面地址
    private static String VIDEO_PAGE_URL = "http://10.3.2.218:8080/online/playVideoPage?id=";
    private static String STORAGE_PATH = "E:/videos/";
    private static String ROOT_PATH = "http://10.3.2.218:8080";

    private static String USERNAME = "admin";
    private static String PASSWORD = "123456";

    private static int THREAD_NO = 6;  // 爬虫线程数量

    public static void main(String[] args) throws IOException {
//        httpDownload("http://xunleib.zuida360.com/1808/YC%E5%A5%BD%E6%88%8F.TC%E6%B8%85%E6%99%B0%E7%89%88.mp4", "E:\\BaiduNetdiskDownload\\ychx.mp4");
        CustomQueue queue = CustomQueue.getInstance();

        getOnlinePage();
        // 保存视频
        for (int i = 0; i < THREAD_NO; i++) {
            new Thread(() -> {
                while (queue.length() != 0) {
                    VideoModel model = (VideoModel)queue.pop();
                    System.out.println(Thread.currentThread().getName() + " 开始下载： " + model.getFilename());
                    httpDownload(model.getUrl(), model.getFilename());
                }
            }).start();
        }

        System.out.println("下载结束");
    }

    /**
     * 获取在线学习主模块
     * @throws IOException
     */
    public static void getOnlinePage() throws IOException {
        // 登录用户名和密码
        Map userinfo = new HashMap();
        userinfo.put("name", USERNAME);
        userinfo.put("password", PASSWORD);

        // 调用 CookieManager 管理 HttpURLConnection 的cookie
        CookieManager manager = new CookieManager();
        CookieHandler.setDefault(manager);

        // 登录
        System.out.println(form(LOGIN_URL, userinfo));
        // 获取在线学习的数据
        Map post = post(LOAD_DATA_URL, null);

        // 根据返回的模块数据创建对应存储视频的文件夹
        JSONArray array = (JSONArray)post.get("data");

        for (Object object : array) {
            // 创建文件夹与说明文档
            Map tmp = JSON.parseObject(JSON.toJSONString(object), Map.class);
            String courseName = (String) tmp.get("courseName");
            createDir(STORAGE_PATH + courseName);
            String introduction = (String) tmp.get("introduction");
            writeIntoFile(STORAGE_PATH + courseName + "/introduction.txt", introduction);
            Integer courseId = (Integer) tmp.get("id");
            getCourseDetail(courseId, STORAGE_PATH + courseName + "/");
        }
    }

    /**
     * 根据课程id 获取详细课程
     * @param courseId
     */
    public static void getCourseDetail(Integer courseId, String storagePath){
        Map courseinfo = new HashMap();
        courseinfo.put("id", courseId);
        try {
            Map post = form(LOAD_CATALOG_LIST, courseinfo);
            // 根据返回的模块数据创建对应存储视频的文件夹
            JSONArray array = (JSONArray)post.get("data");

            for (Object object : array) {
                // 创建文件夹与说明文档
                Map tmp = JSON.parseObject(JSON.toJSONString(object), Map.class);
                String chapterName = (String) tmp.get("chapterName");
                String introduction = (String) tmp.get("introduction");
                String courseLength = (String) tmp.get("courseLength");
                String chapterId = tmp.get("id").toString();

                String videoName = chapterId +
                        "__" + chapterName + (introduction == null ? "" : introduction) + ".mp4";

                // 根据章节id获取对应章节视频所在的页面
                String videoUrl = getVideoUrl(chapterId);
                CustomQueue queue = CustomQueue.getInstance();
                queue.push(new VideoModel(ROOT_PATH + videoUrl, storagePath + videoName));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 根据章节id获取对应章节视频所在的页面
     * @param chapterId 章节 ID
     */
    public static String getVideoUrl(String chapterId) {
        try {
            // 视屏地址
            String result = get(VIDEO_PAGE_URL + chapterId, "text/html;charset=UTF-8", 20000, 20000);
            result = result.substring(result.indexOf("<video src=\"") + "<video src=\"".length(), result.indexOf("controls") - 2);
            return result;
        } catch (IOException e) {
            e.printStackTrace();
        }

        return null;
    }

    public static void createDir(String dirName) {
        File file = new File(dirName);
        if (!file.exists()) {
            file.mkdirs();
        }
    }

    public static void writeIntoFile(String filename, String content) {
        try {
            FileOutputStream fileOutputStream = new FileOutputStream(filename);
            OutputStreamWriter writer = new OutputStreamWriter(fileOutputStream);
            writer.write(content);
            writer.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     *
     * @param url 请求地址
     * @param param 请求参数
     * @param contentType
     * @param connTimeout
     * @param readTimeout
     * @return
     * @throws IOException
     */
    public static Map post(String url, Map param, String contentType, int connTimeout, int readTimeout) throws IOException {
        // 获取 URL 对象
        URL urlObj = new URL(url);
        // 打开 URL 之间的链接
        HttpURLConnection connection = (HttpURLConnection)urlObj.openConnection();


        // 设置通用请求属性
        connection.setConnectTimeout(connTimeout);
        connection.setReadTimeout(readTimeout);
        connection.setUseCaches(false); // 不使用缓存
        connection.setDoInput(true); // 允许输入
        connection.setDoOutput(true); // 允许输出
        connection.setRequestProperty("Charset", "UTF-8");
        connection.setRequestMethod("POST"); // 设置请求方法
        connection.setRequestProperty("Content-type", contentType);

        // 显示连接
        connection.connect();

        // application/x-www-form-urlencoded; charset=UTF-8
        if (contentType.contains("form")) {
            //  提交 form 表单数据
            StringBuilder builder = new StringBuilder();
            if (param != null) {
                Set<String> keySet = param.keySet();
                for (String key :keySet) {
                    builder.append(key);
                    builder.append("=");
                    builder.append(URLEncoder.encode(param.get(key).toString(),"UTF-8"));
                    builder.append("&");
                }
                //name=admin&password=123456&
                builder.deleteCharAt(builder.length() - 1);
                // name=admin&password=123456
            }

            //建立输入流，向指向的URL传入参数
            DataOutputStream dos = new DataOutputStream(connection.getOutputStream());
            dos.writeBytes(builder.toString());
            dos.flush();
            dos.close();
        } else if (contentType.contains("json")) {
            // 建立输入流
        OutputStreamWriter writer = new OutputStreamWriter(connection.getOutputStream(), "UTF-8");
        // 发送参数
        writer.write(JSON.toJSONString(param));
        // 清理当前编辑器的左右缓冲区，并使缓冲区数据写入基础流
        writer.flush();
    }

        BufferedReader reader = new BufferedReader(
                new InputStreamReader(connection.getInputStream(), "UTF-8"));

        List lines = Arrays.asList(reader.lines().toArray()); // 读取请求结果
        reader.close();
        Map result = JSON.parseObject(String.join("", lines), Map.class);
        return result;
    }

    public static String get(String url, String contentType, int connTimeout, int readTimeout) throws IOException {
        // 获取 URL 对象
        URL urlObj = new URL(url);
        // 打开 URL 之间的链接
        HttpURLConnection connection = (HttpURLConnection)urlObj.openConnection();
        // 设置通用请求属性
        connection.setConnectTimeout(connTimeout);
        connection.setReadTimeout(readTimeout);
        connection.setUseCaches(false); // 不使用缓存
        connection.setDoInput(true); // 允许输入
        connection.setDoOutput(true); // 允许输出
        connection.setRequestProperty("Charset", "UTF-8");
        connection.setRequestMethod("GET"); // 设置请求方法
        connection.setRequestProperty("Content-type", contentType);
        connection.setRequestProperty("Referrer Policy", "no-referrer-when-downgrade");


        // 读取数据
        BufferedReader reader = new BufferedReader(
                new InputStreamReader(connection.getInputStream(), "UTF-8"));

        // 显示连接
        connection.connect();
        StringBuffer buffer = new StringBuffer();
        reader.lines().forEach(line -> {
            buffer.append(line);
            buffer.append("\n");
        });

        return buffer.toString();
    }

    /**
     * 下载视屏并保存
     * @param httpUrl
     * @param savePath
     * @return
     */
    public static boolean httpDownload(String httpUrl,String savePath){
        // 下载网络文件
        int bytesum = 0;
        int byteread = 0;

        URL url = null;
        try {
            url = new URL(httpUrl);
        } catch (MalformedURLException e1) {
            e1.printStackTrace();
            return false;
        }

        try {
            URLConnection conn = url.openConnection();
            InputStream inStream = conn.getInputStream();
            FileOutputStream fs = new FileOutputStream(savePath);

            byte[] buffer = new byte[1204];
            while ((byteread = inStream.read(buffer)) != -1) {
                bytesum += byteread;
                fs.write(buffer, 0, byteread);
            }
            return true;
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            return false;
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
    }





















    public static Map post(String url, Map param, String contentType) throws IOException {
        return post(url, param, contentType, 20000, 20000);
    }

    /**
     * 该方法会将传入的 map 数据转换成 UTF-8 的 JSON 数据，
     * 并将数据放入 http 请求的body中，以 row 格式的json传到服务端,
     * row 格式的数据是纯字符串的数据上传方式，需要 @RequestBody 将json 再次进行转换
     *
     * @param url
     * @param param
     * @return
     * @throws IOException
     */
    public static Map post(String url, Map param) throws IOException {
        return post(url, param, "application/json;charset=UTF-8");
    }

    public static Map form(String url, Map param) throws IOException {
        return post(url, param, "application/x-www-form-urlencoded; charset=UTF-8");
    }
}
